from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem,QGraphicsRectItem,QFileDialog
from PyQt5.QtGui import QPixmap,QPen,QBrush,QColor
from PyQt5.QtCore import Qt,QRectF,QPointF,pyqtSignal

class ImageViewer(QGraphicsView):
    rect_selected = pyqtSignal(dict)  # 添加信号用于发送矩形参数
    del_selected = pyqtSignal()  # 添加信号用于发送矩形参数
    color_selected = pyqtSignal(str,QPointF)
    
    def __init__(self, image_path):
        super().__init__()
      
        self.image_path = image_path
        self.min_zoom = 0.2
        self.max_zoom = 10.0    
        self.alt_pressed = False # 用于判断是否按下了Alt键
        self.alt_escape = False # 用于判断是否按下了Alt+Escape键

        
        self.is_selecting = False # 跟踪鼠标是否正在拖拽选择
        self.start_point = QPointF()
        self.current_rect = None  # 选择矩形
        self.relative_rect = None  # 存储单个矩形的相对坐标
        
        # 获取图像的原始尺寸
        self.original_size = QPixmap(image_path).size()


        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)

        self.setDragMode(QGraphicsView.NoDrag)  # 强制设置 不启用拖动
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.viewport().setCursor(Qt.ArrowCursor)

        self.load_image()

   
    def load_image(self):
        self.scene.clear()
        if not self.image_path:
            return
        pixmap = QPixmap(self.image_path)
        self.pixmap = pixmap  # 保存pixmap引用
        item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(item)
        self.fitInView(item, Qt.KeepAspectRatio)

    def wheelEvent(self, event):

        # 获取当前缩放因子
        current_zoom = self.transform().m11()

         # 根据滚轮方向计算新的缩放因子
        if event.angleDelta().y() > 0:
            # 放大
            new_zoom = current_zoom * 1.1
        else:
            # 缩小
            new_zoom = current_zoom / 1.1

         # 限制缩放范围
        new_zoom = max(self.min_zoom, min(new_zoom, self.max_zoom))
        
        # 应用新的缩放因子
        self.resetTransform()
        self.scale(new_zoom, new_zoom)

    def mousePressEvent(self, event):
        """处理鼠标按下事件"""
        if event.button() == Qt.LeftButton and self.alt_pressed: 
             # 如果已有矩形，先删除
            if self.current_rect:
                self.scene.removeItem(self.current_rect)
                self.current_rect = None
                self.current_rect_param = None
                self.relative_rect = None

            # 将视图坐标转换为场景坐标
            self.start_point = self.mapToScene(event.pos())
            # 创建新的矩形项
            self.current_rect = QGraphicsRectItem()
            # 设置矩形样式
            pen = QPen(QColor(255, 0, 0))
            pen.setStyle(Qt.DashLine)
            self.current_rect.setPen(pen)
            self.scene.addItem(self.current_rect)
            self.is_selecting = True
            return
        
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """处理鼠标移动事件"""
        if  self.is_selecting and event.buttons() and self.current_rect and Qt.LeftButton:
            # 将视图坐标转换为场景坐标
            current_point = self.mapToScene(event.pos())
            rect = QRectF(self.start_point, current_point).normalized()
            self.current_rect.setRect(rect)
            return
        
        super().mouseMoveEvent(event)    

    def start_selection(self, pos):
        """开始矩形选择"""
        self.start_pos = pos
        # 创建选择矩形
        self.selection_rect = QGraphicsRectItem(QRectF(pos, QPointF(0, 0)))
        # 设置选择矩形样式
        pen = QPen(Qt.GlobalColor.darkBlue, 1, Qt.PenStyle.DashLine)
        brush = QBrush(QColor(100, 100, 255, 50))  # 半透明蓝色
        self.selection_rect.setPen(pen)
        self.selection_rect.setBrush(brush)
        self.scene.addItem(self.selection_rect)
        
        # 清除之前的选择
        #self.clear_selection()   

    def update_selection(self, pos):
        """更新选择矩形"""
        if self.selection_rect and self.start_pos:
            # 计算选择矩形的范围
            current_point = self.mapToScene(event.pos())
            rect = QRectF(self.start_pos, current_point).normalized()
            self.selection_rect.setRect(rect)
         
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):

        if event.button() == Qt.RightButton:
            #获取色值与坐标 
            pos = event.pos()
            scene_pos = self.mapToScene(pos)
            item = self.scene.itemAt(scene_pos, self.transform())
            if item:
                # 假设item是QGraphicsPixmapItem
                pixmap = item.pixmap()
                if not pixmap.isNull():
                    color = pixmap.toImage().pixelColor(scene_pos.toPoint())
                    self.color_selected.emit(color.name(),scene_pos)
            return

        if event.button() == Qt.LeftButton and self.is_selecting and self.current_rect:
            self.is_selecting = False
            # 更改样式为实线
            pen = QPen(QColor(255, 0, 0))
            self.current_rect.setPen(pen)
            
            # 计算矩形参数
            rect = self.current_rect.rect()
            x = rect.x()
            y = rect.y()
            width = rect.width()
            height = rect.height()
            
            # 计算相对坐标（百分比）
            if self.original_size.width() > 0 and self.original_size.height() > 0:
                # 获取当前视图到场景的变换矩阵
                view_to_scene = self.transform().inverted()[0]
                # 计算场景到图像的缩放因子
                scene_to_image = self.original_size.width() / self.scene.itemsBoundingRect().width()
                
                # 计算矩形在原始图像中的绝对坐标
                abs_x = x * scene_to_image
                abs_y = y * scene_to_image
                abs_width = width * scene_to_image
                abs_height = height * scene_to_image
                
                # 计算相对坐标
                rel_x = abs_x / self.original_size.width()
                rel_y = abs_y / self.original_size.height()
                rel_width = abs_width / self.original_size.width()
                rel_height = abs_height / self.original_size.height()
                
                # 发送矩形参数信号
                self.current_rect_param = {
                    'x': abs_x,
                    'y': abs_y,
                    'width': abs_width,
                    'height': abs_height,
                    'rel_x': rel_x,
                    'rel_y': rel_y,
                    'rel_width': rel_width,
                    'rel_height': rel_height
                }
                self.rect_selected.emit(self.current_rect_param)
                
        super().mouseReleaseEvent(event)  

    def keyPressEvent(self, event):
        # 检测Alt键按下
        if event.key() == Qt.Key_Alt:
            self.alt_pressed = True

        if event.key() == Qt.Key_Control:
            self.alt_escape = True
            self.setDragMode(QGraphicsView.ScrollHandDrag)
            #print('开启拖动')
            #print('dragMode',self.dragMode())
          
            
    def keyReleaseEvent(self, event):
        # 检测Alt键释放
        if event.key() == Qt.Key_Alt:
            self.alt_pressed = False

        if event.key() == Qt.Key_Control:
            self.alt_escape = False  
            self.setDragMode(QGraphicsView.NoDrag)
            #print('关闭拖动')
            #print('dragMode',self.dragMode())
            
        if event.key() == Qt.Key_Escape:
             # 如果已有矩形，先删除
            if self.current_rect:
                self.scene.removeItem(self.current_rect)
                self.current_rect = None
                self.relative_rect = None
                self.del_selected.emit()
            

    def crop_img(self):
        if self.current_rect:
            rect = self.current_rect.rect()
            
            # 计算矩形参数
            x = rect.x()
            y = rect.y()
            width = rect.width()
            height = rect.height()
            
            # 计算在原始图像中的绝对坐标
            if self.original_size.width() > 0 and self.original_size.height() > 0:
                # 获取当前视图到场景的变换矩阵
                view_to_scene = self.transform().inverted()[0]
                # 计算场景到图像的缩放因子
                scene_to_image = self.original_size.width() / self.scene.itemsBoundingRect().width()
                
                # 计算矩形在原始图像中的绝对坐标
                abs_x = int(x * scene_to_image)
                abs_y = int(y * scene_to_image)
                abs_width = int(width * scene_to_image)
                abs_height = int(height * scene_to_image)
                
                # 加载原始图像并裁剪
                original_pixmap = QPixmap(self.image_path)
                cropped_pixmap = original_pixmap.copy(abs_x, abs_y, abs_width, abs_height)
                
                # 返回裁剪后的图像
                return cropped_pixmap
        
        return None

    def save_img(self):
        #另存图片
        options = QFileDialog.Options()
        fileName, _ = QFileDialog.getSaveFileName(self, "另存为", "", "图像文件 (*.png *.jpg *.jpeg)", options=options)
        if fileName:
            self.pixmap.save(fileName)

    def getRectParam(self):
        if self.current_rect and self.current_rect_param:
            return self.current_rect_param
        else:
            return None        
          

             

   